home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
dev
/
sun4.md
/
devATC.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
52KB
|
1,887 lines
/*
* devATC.c --
*
* Driver the for ATC controller.
*
* Copyright 1990 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/sun4.md/devATC.c,v 9.2 92/10/23 15:04:35 elm Exp $ SPRITE (Berkeley)";
#endif /* not lint */
/* all include files in /sprite/lib/include unless otherwise specified */
#include <sys/types.h>
#include "sprite.h"
#include "mach.h" /* /sprite/src/mach/sun4.md */
#include "dev.h" /* /sprite/src/kernel/dev */
#include "devInt.h" /* /sprite/src/kernel/dev/sun4.md */
#include "devDiskLabel.h" /* /sprite/src/kernel/dev */
#include "dbg.h" /* /sprite/src/kernel/dbg/sun4.md */
#include "vm.h"
#include "sys.h"
#include "sync.h"
#include "fs.h" /* /sprite/src/kernel/fs/fs.h */
#include "vmMach.h" /* /sprite/src/lib/include/sun4.md/vmMach.h */
#include "devQueue.h" /* /sprite/src/kernel/dev */
#include "devBlockDevice.h" /* /sprite/src/kernel/dev */
#include "devDiskStats.h" /* /sprite/src/kernel/dev */
#include "stdlib.h"
#include "iopb.h"
#include "atcreg.h"
#include "atc.h"
#include "devATC.h"
/*
#define DEBUG
*/
static atcDebug = TRUE;
static sentTables = 0;
#ifndef NUM_IOPBS
#define NUM_IOPBS MAX_IOPBS /* # of IOPBs allocated per ctrlr */
#endif
#ifndef RBURSTSZ
#define RBURSTSZ 8192 /* VME DMA read burst size */
#endif
#ifndef WBURSTSZ
#define WBURSTSZ 8192 /* VME DMA write burst size */
#endif
#ifndef VMETIMEOUT
#define VMETIMEOUT 100 /* VME bus timeout (in ms.) */
#endif
#ifndef TD_FLAGS
#define TD_FLAGS 0 /* primary w/o block mode, by default */
#endif
#ifndef NATC
#define NATC 4
#endif
/*
#ifndef ATC_MAX_DISKS
#define ATC_MAX_DISKS 1
#endif
*/
#ifndef ATC_MAX_DISKS
#define ATC_MAX_DISKS (5*7)
#endif
#define TOTAL_CYL (900 * 5)
#define HEADS_PER_CYL 14
#define SECTORS_PER_TRACK 48
/*
* Unit = (3 bits for controller, 6 bits for volume, 4 bits for partition)
*/
#define MAXCTRL NATC /* max taken from the configuration */
#define MAXVOL 64 /* up to 64 logical volumes */
#define CTRL(m) (((m)>>10) & 0x7)/* controller number */
#define VOL(m) (((m)>>4) & 0x3f)/* volume number */
#define DIAG_VOL 63 /* reserved volume for diagnostics */
#define SECTOR_SIZE 512
/*
* Define 'AMOD', the address modifier the Array should use for its DMA
*/
#define AMOD 0x3d
#define A24AMOD 0x3d /* vmea24 single word */
#define A32WAMOD 0x0d
#define A32BAMOD 0x0f /* vmea32 block mode */
/*
* Unless I decide to include a buf structure of my own, I need to
* change this and identify the special bit soemwhere else!
* We need a bit in the buffer 'flags' field to mark special commands.
* The following determines which bit we grab. Newer versions of RISC/os
* define B_SPECIAL in <sys/buf.h> so we have to be careful here.
*/
#define B_SPECIAL 0x80000000
#define IS_SPECIAL(bp) ((bp)->b_flags & B_SPECIAL)
#define GET_ETYPE(e) (((e)>>24) & 0xff)
#define GET_ESTATUS(e) (((e)>>16) & 0xff)
#define GET_ECMD(e) (((e)>>8) & 0xff)
#define GET_ECODE(e) (((e)>>0) & 0xff)
/* Error types */
#define ET_CMD_SPEC 0x00
#define ET_CMD_GEN 0x01
#define ET_ENVIRON 0x02
#define ET_INFO 0x03
#define ET_BKD_DIAG 0x04
#define ET_ABORT 0x05
#define ET_INIT 0x06
/* Error status */
#define ES_EMPTY 0x00
#define ES_SENSE_VALID 0x01
#define ES_NONFATAL 0x02
#define ES_EXT_VALID 0x04
#define ES_PASS_THRU 0x08
/* Error Codes */
/* Generic codes */
#define EC_CMD 0x01 /* invalid command */
#define EC_OPTION 0x02 /* invalid option */
#define EC_PRIORITY 0x03 /* invalid priority */
#define EC_LINK 0x04 /* invalid linked_iopb */
#define EC_FLAGS 0x05 /* invlaid flags */
#define EC_ID 0x06 /* invlaid id field */
#define EC_LOG_BLK 0x07 /* invlaid logical block */
#define EC_BYTE_CNT 0x08 /* invlaid byte count */
#define EC_BUFFER 0x09 /* invalid buffer address */
#define EC_BUFADDRMOD 0x0a /* invalid buffer address modifier */
#define EC_INT_LEVEL 0x0b /* invalid interrupt level */
#define EC_AUXBUFMOD 0x0c /* invalid aux buffer modifier */
#define EC_SG_ENTRIES 0x0d /* invalid scatter-gather entries */
#define EC_AUXBUFSIZE 0x0e /* invalid aux buffer size */
#define EC_AUXBUFFER 0x0f /* invalid aux buffer */
#define EC_SG_COUNT 0x10 /* invalid count in sg_struct */
#define EC_SG_BUFFER 0x11 /* invalid buffer in sg_struct */
#define EC_SG_AMOD 0x12 /* invalid addr mod in s.g. entry */
#define EC_BFR_AND_SIZE 0x19 /* buffer and size conflict */
#define EC_BFR_AND_SG 0x1a /* buffer and scatter/gather conflict */
#define EC_BFR_AND_CHKSUM 0x1b /* buffer and checksum conflict */
/* stask.b Error Codes */
#define EC_SCSI 0x29 /* a SCSI error occurred */
#define EC_DEV_OFFLINE 0x2a /* device is offline */
#define EC_DEV_TIMEOUT 0x2b /* SCSI REQUEST TIMED OUT */
#define EC_DEV_REBUILDING 0x2c /* device is being rebuilt
/*
* The ATC_RAW_READ and ATC_RAW_WRITE commands return sector header
* information that looks like the following struct. Again, this
* is byte-swapped in comparison with the documentation.
*
* A raw read is done during boot strap to determine the drive type.
* The label is read at the same time to determine the disk geometry,
* and this information is passed back into the controller.
*/
typedef struct ATCSectorHeader {
/*
* Byte 1
*/
char sectorHigh :2;
char reserved :3;
char cylHigh :3;
/*
* Byte 0
*/
char cylLow :8;
/*
* Byte 3
*/
char driveType :2;
char sectorLow :6;
/*
* Byte 2
*/
char head :8;
} ATCSectorHeader;
typedef struct ATCDisk ATCDisk;
typedef struct Request Request;
struct perRequestInfo {
Request *requestPtr; /* pointer to request info */
Address dmaBuffer; /* pointer to dma buffer */
int dmaBufferSize; /* size of dma buffer */
struct iopbhdr *IOPBPtr; /* pointer to IOPB structure for request */
} perRequestInfo;
typedef struct ATCController {
volatile ATCRegs *regsPtr; /* Pointer to Controller's registers */
int number; /* Controller number, 0, 1 ... */
Sync_Semaphore mutex; /* Mutex for queue access */
Sync_Condition specialCmdWait; /* Condition to wait of for special
* commands liked test unit ready and
* reading labels. */
int numSpecialWaiting; /* Number of processes waiting to
* get access to the controller for
* a sync command. */
DevCtrlQueues ctrlQueues; /* Queues of disk attached to the
* controller. */
ATCDisk *disks[ATC_MAX_DISKS]; /* Disk attached to the
* controller. */
u_long flags; /* controller state information */
#define F_PRESENT 0x0001 /* device exists */
#define F_INIT 0x0002 /* device got init. block */
#define F_NEED_IOPB 0x0004 /* someone waiting for IOPB */
#define F_IN_USE 0x0008 /* opened for normal I/O */
#define F_DIAGS 0x0010 /* opened for diagnostics */
#define F_FIFO_DATA 0x0020 /* FIFO data avail (diags) */
u_long debug; /* controller debug flags */
#define D_DEBUG 0x0001 /* enable most printfs */
#define D_SINGLE_REQ 0x0002 /* single-request mode */
#define D_TIMEOUTS 0x0004 /* enable IOPB timeouts */
#define D_STIMEOUTS 0x0008 /* show timeouts */
int numActiveIOPBs; /* number of outstanding IOPBs */
int maxActive; /* most IOPBs ever active at a time */
int ilev; /* interrupt level */
int ivec; /* interrupt vector */
int fifo_data; /* last byte read (during diags) */
int diag_buf[DBUFSZ]; /* buffer for diagnostics */
u_long vol_sizes[MAXVOL]; /* volume sizes */
struct dstats ds; /* driver statistics */
struct iopbhdr *free_iopbs; /* head of linked IOPB list */
/*
* IOPBs and their corresponding status blocks are dynamically
* allocated in the following arrays. Error status for a given
* IOPB is returned in the status structure of the same index.
*/
struct iopbhdr *iopblist;
struct status *statuslist;
/*
* The IOPB and status tables contain pointers to the IOPBs and
* status structures in the arrays above. The host DMAs the
* following arrays during initialization so it knows where to
* find everything in host memory.
*/
struct iopb_table *iopb_table;
struct status_table *status_table;
/*
* The table descriptor contains pointers to the IOPB and status
* tables as well as some other controller information. We shove
* this directly through the command FIFO during initialization.
*/
struct table_desc td; /* the table descriptor */
Address diag_buf_addr; /* DMA address of the buffer */
/*
* This is a pointer to the iopblist array as it is mapped into
* DMA space.
*/
struct iopbhdr *iopblistp;
struct status *statuslistp;
struct perRequestInfo requestInfo[NUM_IOPBS];
} ATCController;
struct ATCDisk {
ATCController *atcPtr; /* Back pointer to controller state */
int atcDriveType; /* ATC code for disk */
int slaveID; /* Drive number */
int numCylinders; /* ... on the disk */
int numHeads; /* ... per cylinder */
int numSectors; /* ... on each track */
DevQueue queue;
DevDiskMap map[DEV_NUM_DISK_PARTS];/* partitions */
DevDiskStats *diskStatsPtr;
};
/*
* The interface to ATCDisk the outside world views the disk as a
* partitioned disk.
*/
typedef struct PartitionDisk {
DevBlockDeviceHandle handle; /* Must be FIRST field. */
int partition; /* Partition number on disk. */
ATCDisk *diskPtr; /* Real disk. */
} PartitionDisk;
/*
* Format of request queued for a ATC disk. This request is
* built in the ctrlData area of the DevBlockDeviceRequest.
*/
struct Request {
List_Links queueLinks; /* For the dev queue modole. */
char command; /* One of the ATC commands */
char option; /* Option qualifies command */
char flags;
ATCDisk *diskPtr; /* Target disk for request. */
int diskAddress; /* Starting address of request. */
int numSectors; /* Number of sectors to transfer. */
Address buffer; /* Memory to transfer to/from. */
int retries; /* Number of retries on the command. */
DevBlockDeviceRequest *requestPtr; /* Block device generating this
* request. */
};
typedef struct _atcIOCParam{
char option;
char arg;
}atcIOCParam;
/*
* This is the state that needs to be maintained for each request.
*/
/*
* State for each ATC controller.
*/
static ATCController *ATC[MAXCTRL];
/*
* This controlls the time spent busy waiting for the transfer completion
* when not in interrupt mode.
*/
#define ATC_WAIT_LENGTH 250000
/*
* Constants related to timeouts
*/
#define WSECS 5
#define WSTART 0 /* start timer */
#define WCONT 1 /* continue timer */
#define REQUEST_COUNT 2 /* number of clock ticks until timeout */
/*
* SECTORS_PER_BLOCK
*/
#define SECTORS_PER_BLOCK (FS_BLOCK_SIZE / DEV_BYTES_PER_SECTOR)
/*
* Forward declarations.
*/
extern void printf();
static void ResetController();
static ReturnStatus TestDisk();
static ReturnStatus ReadDiskLabel();
static void SetupIOPB();
static void RequestDone();
static void StartNextRequest();
static void FillInDiskTransfer();
/*
*----------------------------------------------------------------------
*
* alloc_iopb --
*
* Start the next request of an ATC controller.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
struct iopbhdr *
alloc_iopb(atcPtr)
register ATCController *atcPtr;
{
struct iopbhdr *iopb;
if (atcDebug){
if (atcDebug) {
printf("Entered alloc_iopb.\n");
}
}
if (atcPtr->free_iopbs == NULL) {
return NULL;
}
iopb = atcPtr->free_iopbs; /* take from head */
atcPtr->free_iopbs = atcPtr->free_iopbs->next_free;/* update head ptr */
atcPtr->numActiveIOPBs++;
if (atcPtr->numActiveIOPBs > atcPtr->maxActive) {
if (atcDebug){
printf("New max IOPBs: %d\n",atcPtr->numActiveIOPBs);
}
}
return iopb;
}
/*
*----------------------------------------------------------------------
*
* free_iopb --
*
* Start the next request of an ATC controller.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
free_iopb(atcPtr, iopb)
register ATCController *atcPtr;
register struct iopbhdr *iopb;
{
if (atcPtr->free_iopbs == NULL) { /* list was empty */
iopb->next_free = NULL;
atcPtr->free_iopbs = iopb;
return;
}
iopb->next_free = atcPtr->free_iopbs; /* put iopb at head */
atcPtr->free_iopbs = iopb;
if (atcPtr->flags & F_NEED_IOPB) {
atcPtr->flags &= ~F_NEED_IOPB;
}
atcPtr->numActiveIOPBs--;
}
/*
*----------------------------------------------------------------------
*
* put_fifo --
*
* Start the next request of an ATC controller.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
put_fifo(atcPtr, data)
register ATCController *atcPtr;
register int data;
{
if (atcDebug){
printf("Entered put_fifo. Writing 0x%x\n", data & 0xffff);
if (atcPtr->debug & D_DEBUG)
printf("put_fifo: writing 0x%x\n", data & 0xffff);
}
atcPtr->regsPtr->write_fifo = data;
}
/*
*----------------------------------------------------------------------
*
* get_fifo --
*
* Start the next request of an ATC controller.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
get_fifo(atcPtr)
register ATCController *atcPtr;
{
int returnVal;
if (atcDebug){
printf("Entered get_fifo.\n");
}
returnVal = (atcPtr->regsPtr->read_fifo & 0x01ff);
if (atcDebug){
printf("Get_fifo returns %x\n",returnVal);
}
return(returnVal);
}
/*
*----------------------------------------------------------------------
*
* send_table --
*
* Start the next request of an ATC controller.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
send_table(atcPtr)
register ATCController *atcPtr;
{
register int i;
register char *p = (char *) &atcPtr->td;
if (atcDebug){
printf("Entered send_table; about to send tables to board\n");
}
MASTER_LOCK(&(atcPtr->mutex));
put_fifo(atcPtr, TABLE_HEADER);
for (i=0; i < sizeof(struct table_desc) ;i++, p++)
put_fifo(atcPtr, *p);
MASTER_UNLOCK(&(atcPtr->mutex));
}
/*
*----------------------------------------------------------------------
*
* SendCommand --
*
* Lower level routine to read or write an ATC device. Use this
* to transfer a contiguous set of sectors. The interface here
* is in terms of a particular ATC disk and the command to be
* sent. This routine takes care of mapping its
* buffer into the special multibus memory area that is set up for
* Sun DMA.
*
* Results:
* An error code.
*
* Side effects:
* Those of the command (Read, write etc.)
*
*----------------------------------------------------------------------
*/
static void
SendCommand(diskPtr, requestPtr, wait, index)
ATCDisk *diskPtr; /* Unit, type, etc, of disk to send command. */
Request *requestPtr; /* Command request block. */
Boolean wait; /* Wait for the command to complete. */
int index;
{
ATCController *atcPtr = diskPtr->atcPtr;
int diskAddr = requestPtr->diskAddress;
int numSectors = requestPtr->numSectors;
Address address = requestPtr->buffer;
/*
* If the command is going to transfer data be relocate the address
* into DMA space.
*/
if (atcDebug){
printf("Entered Send_Command.\n");
}
SetupIOPB(requestPtr, diskPtr, diskAddr, numSectors,
address, &(atcPtr->iopblist[index]));
if (atcDebug){
printf("Contents of iopb about to be sent to board:\n");
printf(" command = 0x%x\n",atcPtr->iopblist[index].iopb.command);
printf(" option = 0x%x\n",atcPtr->iopblist[index].iopb.option);
printf(" priority = 0x%x\n",atcPtr->iopblist[index].iopb.priority);
printf(" reserved1 = 0x%x\n",atcPtr->iopblist[index].iopb.reserved1);
printf(" flags = 0x%x\n",atcPtr->iopblist[index].iopb.flags);
printf(" log_array = 0x%x\n",atcPtr->iopblist[index].iopb.log_array);
printf(" reserved2 = 0x%x\n",atcPtr->iopblist[index].iopb.reserved2);
printf(" id = 0x%x\n",atcPtr->iopblist[index].iopb.id);
printf(" logical_block = 0x%x\n",atcPtr->iopblist[index].iopb.logical_block);
printf(" byte_count = 0x%x\n",atcPtr->iopblist[index].iopb.byte_count);
printf(" buffer = 0x%x\n",atcPtr->iopblist[index].iopb.buffer);
printf(" buf_addr_mod = 0x%x\n",atcPtr->iopblist[index].iopb.buf_addr_mod);
printf(" intr_level = 0x%x\n",atcPtr->iopblist[index].iopb.intr_level);
printf(" intr_vector = 0x%x\n",atcPtr->iopblist[index].iopb.intr_vector);
printf(" auxbuf_mod = 0x%x\n",atcPtr->iopblist[index].iopb.auxbuf_mod);
printf(" sg_entries = 0x%x\n",atcPtr->iopblist[index].iopb.sg_entries);
printf(" auxbuf_size = 0x%x\n",atcPtr->iopblist[index].iopb.auxbuf_size);
printf(" aux_buffer = 0x%x\n",atcPtr->iopblist[index].iopb.aux_buffer);
}
/*
* Start up the controller by pushing index of iopb onto fifo.
*/
put_fifo(atcPtr, index);
if (atcDebug){
printf("In Send_Command: Wrote index to down_fifo.\n");
}
}
/*
*----------------------------------------------------------------------
*
* atcEntryAvailProc --
*
* Act upon an entry becomming available in the queue for a
* device.. This routine is the Dev_Queue callback function that
* is called whenever work becomes available for a device.
* If the controller is not already busy we dequeue and start the
* request.
*
* Results:
* TRUE if the request is processed. FALSE if the request should be
* enqueued.
*
* Side effects:
* Request may be dequeue and submitted to the device. Request callback
* function may be called.
*
*----------------------------------------------------------------------
*/
static Boolean
atcEntryAvailProc(clientData, newRequestPtr)
ClientData clientData; /* Really the Device this request ready. */
List_Links *newRequestPtr; /* The new request. */
{
register ATCDisk *diskPtr = (ATCDisk *) clientData ;
ATCController *atcPtr = diskPtr->atcPtr;
register Request *requestPtr = (Request *) newRequestPtr;
struct iopbhdr *iopbhdrPtr;
int index;
if (atcDebug){
printf("Entered atcEntryAvailProc.\n");
}
if (requestPtr->numSectors == 0) {
MASTER_UNLOCK(&atcPtr->mutex);
RequestDone(requestPtr->diskPtr, requestPtr, SUCCESS, 0);
MASTER_LOCK(&atcPtr->mutex);
return TRUE;
}
/* actEntryAvailProc is called with master locks held
MASTER_LOCK(&atcPtr->mutex);
*/
iopbhdrPtr = alloc_iopb(atcPtr);
index = iopbhdrPtr->index;
/*
MASTER_UNLOCK(&atcPtr->mutex);
*/
if (iopbhdrPtr == NULL) {
return(FALSE);
}
MASTER_UNLOCK(&atcPtr->mutex);
SendCommand(diskPtr, requestPtr, FALSE, index);
MASTER_LOCK(&atcPtr->mutex);
if (atcDebug){
printf("In atcEntryAvailProc: Returned from SendCommand.\n");
}
return(TRUE);
}
/*
*----------------------------------------------------------------------
*
* DevATCInit --
* Main thing to do here is appropriately malloc everything and
* map appropriate stuff into dma space.
* Initialize an ATC controller.
*
* Results:
* A NIL pointer if the controller does not exists. Otherwise a pointer
* the the ATCController stucture.
*
* Side effects:
* Map the controller into kernel virtual space.
* Allocate buffer space associated with the controller.
* Do a hardware reset of the controller.
*
*----------------------------------------------------------------------
*/
ClientData
DevATCInit(cntrlrPtr)
DevConfigController *cntrlrPtr; /* Config info for the controller */
{
ATCController *atcPtr; /* ATC specific state */
register volatile ATCRegs *regsPtr;/* Control registers for ATC */
short x; /* Used when probing the controller */
int i;
ReturnStatus status;
/*
* Poke at the controller's registers to see if it works
* or we get a bus error.
* Mach_Probe(int byteCount, Address readAddress, Address writeAddress)
* returns ReturnStatus.
*/
regsPtr = (volatile ATCRegs *) cntrlrPtr->address;
if (atcDebug){
printf("In DevATCInit: regsPtr = %x\n",regsPtr);
}
status = Mach_Probe(sizeof(regsPtr->read_fifo),
(char *) &(regsPtr->read_fifo), (char *) &x);
if (status != SUCCESS) {
printf("ATC%d NOT found.\n", cntrlrPtr->controllerID);
return DEV_NO_CONTROLLER;
}
#ifdef notdef
/*
* Don't write into fifo.
*/
status = Mach_Probe(sizeof(regsPtr->write_fifo), "x",
(char *) &(regsPtr->write_fifo));
if (status != SUCCESS) {
return DEV_NO_CONTROLLER;
}
#endif
/*
* Allocate and initialize the controller state info.
*/
atcPtr = (ATCController *)malloc(sizeof(ATCController));
bzero((char *) atcPtr, sizeof(ATCController));
ATC[cntrlrPtr->controllerID] = (ATCController *)atcPtr;
atcPtr->regsPtr = regsPtr;
atcPtr->number = cntrlrPtr->controllerID;
atcPtr->ivec = cntrlrPtr->vectorNumber;
atcPtr->ilev = 3;
atcPtr->flags = 0;
atcPtr->debug = D_TIMEOUTS|D_STIMEOUTS;
for (i=0; i < MAXVOL ;i++)
atcPtr->vol_sizes[i] = 0;
atcPtr->vol_sizes[0] = 10000000;
/*
* Allocate the mapped DMA memory for the IOPBs and status table
* entries. This memory should not be freed unless the controller
* is not going to be accessed again.
*/
{
static Address linkMemAddress[4] =
/*
{(Address) 0, (Address) 0, (Address) 0, (Address) 0};
*/
{(Address) 0xff9e0000, (Address) 0xff9f0000, (Address) 0, (Address) 0};
int bufferSize;
Address hostAddr;
Address deviceAddr;
Address tempBuffer;
int addrOffset;
bufferSize = NUM_IOPBS * (sizeof(struct iopbhdr) + sizeof(struct status) +
sizeof(struct iopb_table) + sizeof(struct status_table));
if (linkMemAddress[cntrlrPtr->controllerID] == 0) {
tempBuffer = malloc(bufferSize);
hostAddr = (Address)VmMach_DMAAlloc(bufferSize, tempBuffer);
deviceAddr = hostAddr - VMMACH_DMA_START_ADDR;
if (hostAddr == (Address) NIL) {
panic("DevATCInit: unable to allocate DMA memory.\n");
}
} else {
deviceAddr = linkMemAddress[cntrlrPtr->controllerID];
hostAddr = (Address) VmMach_MapInBigDevice(deviceAddr, 0x00010000,
VMMACH_TYPE_VME32DATA);
}
printf("IOPBs (size: %d bytes) mapped host=0x%x, device=0x%x\n",
bufferSize, hostAddr, deviceAddr);
atcPtr->iopblist = (struct iopbhdr *) hostAddr;
atcPtr->iopblistp = (struct iopbhdr *) deviceAddr;
addrOffset = NUM_IOPBS * sizeof(struct iopbhdr);
atcPtr->statuslist = (struct status *) (hostAddr + addrOffset);
atcPtr->statuslistp = (struct status *) (deviceAddr + addrOffset);
addrOffset += NUM_IOPBS * sizeof(struct status);
atcPtr->iopb_table = (struct iopb_table *) (hostAddr + addrOffset);
atcPtr->td.iopb_list = (struct iopb_table *) (deviceAddr + addrOffset);
addrOffset += NUM_IOPBS * sizeof(struct iopb_table);
atcPtr->status_table = (struct status_table *) (hostAddr + addrOffset);
atcPtr->td.status_list = (struct status_table *) (deviceAddr + addrOffset);
atcPtr->td.vme_timeout = VMETIMEOUT;
atcPtr->td.iopb_list_mod = AMOD;
atcPtr->td.num_iopbs = NUM_IOPBS;
atcPtr->td.status_list_mod = AMOD;
atcPtr->td.flags = TD_FLAGS;
atcPtr->td.reserved = 0;
atcPtr->td.rdma_burst_sz = RBURSTSZ;
atcPtr->td.wdma_burst_sz = WBURSTSZ;
for (i=0; i < NUM_IOPBS; i++) {
atcPtr->iopb_table[i].iopb_ptr = &atcPtr->iopblistp[i].iopb;
atcPtr->iopb_table[i].iopb_addr_mod = AMOD;
atcPtr->status_table[i].status_ptr = &atcPtr->statuslistp[i];
atcPtr->status_table[i].status_addr_mod = AMOD;
}
atcPtr->numActiveIOPBs = 0;
atcPtr->maxActive = 0;
atcPtr->free_iopbs = NULL;
for (i=0; i < NUM_IOPBS ;i++) {
atcPtr->iopblist[i].index = i;
free_iopb(atcPtr, &atcPtr->iopblist[i]);
}
}
if (atcDebug){
printf("table_desc.iopb_list = 0x%x\n", atcPtr->td.iopb_list);
printf("table_desc.status_list = 0x%x\n", atcPtr->td.status_list);
printf("table_desc.iopb_list_mod = 0x%x\n", AMOD);
printf("table_desc.status_list_mod = 0x%x\n", AMOD);
printf("table_desc.num_iopbs = %d\n", NUM_IOPBS);
}
atcPtr->flags |= F_PRESENT;
Sync_SemInitDynamic(&atcPtr->mutex,"Dev:ATC mutex");
atcPtr->numSpecialWaiting = 0;
atcPtr->ctrlQueues =Dev_CtrlQueuesCreate(&atcPtr->mutex, atcEntryAvailProc);
for (i = 0 ; i < ATC_MAX_DISKS ; i++) {
atcPtr->disks[i] = (ATCDisk *) NIL;
}
return( (ClientData) atcPtr);
}
/*
*----------------------------------------------------------------------
*
* ReleaseProc --
* Device release proc for controller.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static ReturnStatus
ReleaseProc(handlePtr)
DevBlockDeviceHandle *handlePtr; /* Handle pointer of device. */
{
PartitionDisk *pdiskPtr = (PartitionDisk *) handlePtr;
if (atcDebug){
printf("Entered ReleaseProc.\n");
}
free((char *) pdiskPtr);
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* IOControlProc --
*
* Do a special operation on a raw SMD Disk.
* Need to put atc iocontrols in here.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
static ReturnStatus
IOControlProc(handlePtr, ioctlPtr, replyPtr)
DevBlockDeviceHandle *handlePtr; /* Handle pointer of device. */
Fs_IOCParam *ioctlPtr; /* Standard I/O Control parameter block */
Fs_IOReply *replyPtr; /* Size of outBuffer and returned signal */
{
PartitionDisk *pdiskPtr = (PartitionDisk *) handlePtr;
register ATCDisk *diskPtr = pdiskPtr->diskPtr;
ATCController *atcPtr = diskPtr->atcPtr;
/*
atcIOCParam *atcIOCParamPtr = (atcIOCParam *)ioctlPtr->inBuffer;
*/
DevBlockDeviceRequest *reqPtr = (DevBlockDeviceRequest *)ioctlPtr->inBuffer;
int amtTransfer;
if (atcDebug){
printf("Entered IOControlProc.\n");
}
switch (ioctlPtr->command) {
case IOC_ATC_DEBUG_ON:
atcDebug = TRUE;
return(SUCCESS);
break;
case IOC_ATC_DEBUG_OFF:
atcDebug = FALSE;
return(SUCCESS);
break;
case CMD_READ_CONF:
return(SUCCESS);
break;
case CMD_WRITE_CONF:
return(SUCCESS);
break;
case IOC_REPOSITION:
/*
* Reposition is ok
*/
return(SUCCESS);
break;
/*
* No disk specific bits are set this way.
*/
/*
case IOC_DEV_ATC_READXBUS:
break;
case IOC_DEV_ATC_WRITEXBUS:
break;
case IOC_DEV_ATC_SSTATS:
return(SUCCESS);
break;
case IOC_DEV_ATC_CSTATS:
return(SUCCESS);
break;
*/
case IOC_DEV_ATC_IO:
if (atcDebug){
printf("operation = %d\n",reqPtr->operation);
printf("startAddress = 0x%x\n",reqPtr->startAddress);
printf("startAddrHigh = 0x%x\n",reqPtr->startAddrHigh);
printf("bufferLen = %d\n",reqPtr->bufferLen);
printf("buffer = 0x%x\n",reqPtr->buffer);
}
Dev_BlockDeviceIOSync(handlePtr, reqPtr, &amtTransfer);
if (amtTransfer != reqPtr->bufferLen){
return(FAILURE);
} else {
return(SUCCESS);
}
break;
case ATC_RESET:
ResetController(atcPtr);
return(SUCCESS);
break;
default:
return(GEN_INVALID_ARG);
}
}
/*
*----------------------------------------------------------------------
*
* BlockIOProc --
* Start a block IO operations on an ATC board.
* Remember that we are treating the queue as a single queue for
* the entire board.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static ReturnStatus
BlockIOProc(handlePtr, requestPtr)
DevBlockDeviceHandle *handlePtr;
DevBlockDeviceRequest *requestPtr;
{
PartitionDisk *pdiskPtr = (PartitionDisk *) handlePtr;
register ATCDisk *diskPtr = pdiskPtr->diskPtr;
register Request *reqPtr = (Request *) requestPtr->ctrlData;
if (atcDebug){
printf("Entered BlockIOProc.\n");
}
if (requestPtr->operation == FS_READ) {
reqPtr->command = CMD_READ;
reqPtr->option = 0;
reqPtr->flags = 0;
} else {
reqPtr->command = CMD_WRITE;
reqPtr->option = 0;
reqPtr->flags = 0;
}
reqPtr->diskPtr = diskPtr;
FillInDiskTransfer(pdiskPtr, requestPtr->startAddress,
(unsigned) requestPtr->bufferLen,
&(reqPtr->diskAddress), &(reqPtr->numSectors));
reqPtr->buffer = requestPtr->buffer;
reqPtr->retries = 0;
reqPtr->requestPtr = requestPtr;
Dev_QueueInsert(diskPtr->queue, (List_Links *) reqPtr);
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* atcIdleCheck --
*
* Routine for the Disk Stats module to use to determine the idleness
* for a disk. I have changed this to look for the F_INUSE or F_DIAG
* flags for the controller. These tell whether the controller is in
* use for normal I/O or for diagnostics.
*
* Results:
* TRUE if the disk pointed to by clientData is idle, FALSE otherwise.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static Boolean
atcIdleCheck(clientData, diskStatsPtr)
ClientData clientData;
DevDiskStats *diskStatsPtr; /* Unused for ATC. */
{
ATCDisk *diskPtr = (ATCDisk *) clientData;
return (!(diskPtr->atcPtr->flags & F_PRESENT));
}
/*
*----------------------------------------------------------------------
*
* DevATCDiskAttach --
*
* Initialize a device hanging off an ATC controller.
*
* Results:
* A DevBlockDeviceHanlde for this disk.
*
* Side effects:
* Disks: The label sector is read and the partitioning of
* the disk is set up. The partitions correspond to device
* files of the same type but with different unit number.
*
*----------------------------------------------------------------------
*/
DevBlockDeviceHandle *
DevATCDiskAttach(devicePtr)
Fs_Device *devicePtr; /* Device to attach. */
{
ReturnStatus error;
ATCController *atcPtr; /* ATC specific controller state */
register ATCDisk *diskPtr;
PartitionDisk *pdiskPtr; /* Partitioned disk pointer. */
int controllerID;
int diskNumber;
if (atcDebug){
printf("Entered DevATCDiskAttach.\n");
}
controllerID = CTRL(devicePtr->unit);
diskNumber = VOL(devicePtr->unit);
if (atcDebug){
printf("AtcDiskAttach unit 0x%x ctrlr %d disk %d\n",
devicePtr->unit, controllerID, diskNumber);
}
atcPtr = (ATCController *)ATC[controllerID];
if (atcPtr == (ATCController *)NIL ||
atcPtr == (ATCController *)0 ||
diskNumber > MAXVOL) {
return ((DevBlockDeviceHandle *) NIL);
}
if (!sentTables){
ResetController(atcPtr);
sentTables = 1;
MACH_DELAY(100000);
}
/*
* Set up a slot in the disk list. We do a malloc before we grab the
* MASTER_LOCK().
*/
diskPtr = (ATCDisk *) malloc(sizeof(ATCDisk));
bzero((char *) diskPtr, sizeof(ATCDisk));
diskPtr->atcPtr = atcPtr;
diskPtr->atcDriveType = 0;
diskPtr->slaveID = diskNumber;
diskPtr->queue = Dev_QueueCreate(atcPtr->ctrlQueues, 1,
DEV_QUEUE_FIFO_INSERT, (ClientData) diskPtr);
MASTER_LOCK(&(atcPtr->mutex));
if (atcPtr->disks[diskNumber] == (ATCDisk *) NIL) {
/*
* See if the disk is really there.
*/
atcPtr->disks[diskNumber] = diskPtr;
error = TestDisk(atcPtr, diskPtr);
if (error == SUCCESS) {
/*
* Look at the zero'th sector for disk information. This also
* sets the drive type with the controller.
*/
error = ReadDiskLabel(atcPtr, diskPtr);
}
if (error != SUCCESS) {
atcPtr->disks[diskNumber] = (ATCDisk *) NIL;
MASTER_UNLOCK(&(atcPtr->mutex));
Dev_QueueDestroy(diskPtr->queue);
free((Address)diskPtr);
return ((DevBlockDeviceHandle *) NIL);
}
MASTER_UNLOCK(&(atcPtr->mutex));
/*
* Register the disk with the disk stats module.
*/
{
Fs_Device rawDevice;
char name[128];
extern int sprintf();
rawDevice = *devicePtr;
rawDevice.unit = rawDevice.unit & ~0xf;
(void) sprintf(name, "atc%d-%d", atcPtr->number, diskPtr->slaveID);
diskPtr->diskStatsPtr = DevRegisterDisk(&rawDevice, name,
atcIdleCheck, (ClientData) diskPtr);
}
} else {
/*
* The disk already exists. Use it.
*/
MASTER_UNLOCK(&(atcPtr->mutex));
Dev_QueueDestroy(diskPtr->queue);
free((Address)diskPtr);
diskPtr = atcPtr->disks[diskNumber];
}
pdiskPtr = (PartitionDisk *) malloc(sizeof(*pdiskPtr));
bzero((char *) pdiskPtr, sizeof(*pdiskPtr));
pdiskPtr->handle.blockIOProc = BlockIOProc;
pdiskPtr->handle.IOControlProc = IOControlProc;
pdiskPtr->handle.releaseProc = ReleaseProc;
pdiskPtr->handle.minTransferUnit = DEV_BYTES_PER_SECTOR;
pdiskPtr->handle.maxTransferSize = 100*1024;
pdiskPtr->partition = DISK_IS_PARTITIONED(devicePtr) ?
DISK_PARTITION(devicePtr) :
WHOLE_DISK_PARTITION;
pdiskPtr->diskPtr = diskPtr;
return ((DevBlockDeviceHandle *) pdiskPtr);
}
/*
*----------------------------------------------------------------------
*
* ResetController --
*
* Reset the controller. This is done by sending down the descriptor
* table to the board through the FIFO.
*
* Results:
* None.
*
* Side effects:
* Reset the controller.
*
*----------------------------------------------------------------------
*/
static void
ResetController(atcPtr)
volatile ATCController *atcPtr;
{
if (atcDebug){
printf("Entered ResetController.\n");
}
send_table(atcPtr);
}
/*
*----------------------------------------------------------------------
*
* TestDisk --
* Get a controller's status to see if it exists. We do not
* test individual disks in this controller.
*
* Results:
* SUCCESS if the device is ok, DEV_OFFLINE otherwise.
*
* Side effects:
* none.
*
*----------------------------------------------------------------------
*/
static ReturnStatus
TestDisk(atcPtr, diskPtr)
ATCController *atcPtr;
ATCDisk *diskPtr;
{
if (atcDebug){
printf("Entered TestDisk.\n");
}
if (atcPtr->flags & F_PRESENT){
return(SUCCESS);
} else {
return(DEV_OFFLINE);
}
}
/*
*----------------------------------------------------------------------
*
* ReadDiskLabel --
*
* Read the label of the disk and record the partitioning info.
*
* For the ATC driver, this is a dummy routine which currently
* specifies a single partition containing all the data available.
*
* Results:
* None.
*
* Side effects:
* Define the disk partitions that determine which part of the
* disk each different disk device uses.
*
*----------------------------------------------------------------------
*/
static ReturnStatus
ReadDiskLabel(atcPtr, diskPtr)
ATCController *atcPtr;
ATCDisk *diskPtr;
{
int part;
if (atcDebug){
printf("Entered ReadDiskLabel.\n");
}
diskPtr->atcDriveType = 1;
diskPtr->numCylinders = TOTAL_CYL;
diskPtr->numHeads = HEADS_PER_CYL;
diskPtr->numSectors = SECTORS_PER_TRACK;
for (part = 0; part < DEV_NUM_DISK_PARTS; part++) {
diskPtr->map[part].firstCylinder = 0;
diskPtr->map[part].numCylinders = TOTAL_CYL;
}
return(SUCCESS);
}
/*
*----------------------------------------------------------------------
*
* FillInDiskTransfer
* Fill in the disk address and number of sectors of a command.
*
* Results:
* None.
*
* Side effects:
* The number of sectors to transfer gets trimmed down if it would
* cross into the next partition.
*
*----------------------------------------------------------------------
*/
static void
FillInDiskTransfer(pdiskPtr, startAddress, length, diskAddrPtr, numSectorsPtr)
PartitionDisk *pdiskPtr; /* Target Disk Partition. */
unsigned int startAddress; /* Starting offset in bytes.*/
unsigned int length; /* Length in bytes. */
int *diskAddrPtr; /* Disk disk address of
* the first sector to transfer */
int *numSectorsPtr; /* The number
* of sectors to transferred. */
{
ATCDisk *diskPtr; /* State of the disk */
int totalSectors; /* The total number of sectors to transfer */
int lastSector; /* Last sector of the partition */
int startSector; /* The first sector of the transfer */
int part; /* Partition number. */
int cylinderSize; /* Size of a cylinder in sectors. */
if (atcDebug){
printf("Entered FillInDiskTransfer.\n");
}
diskPtr = pdiskPtr->diskPtr;
part = pdiskPtr->partition;
cylinderSize = diskPtr->numHeads * diskPtr->numSectors;
/*
* Do bounds checking to keep the I/O within the partition.
* sectorZero is the sector number of the first sector in the partition,
* lastSector is the sector number of the last sector in the partition.
* (These sector numbers are relative to the start of the partition.)
*/
lastSector = diskPtr->map[part].numCylinders * cylinderSize - 1;
totalSectors = length/DEV_BYTES_PER_SECTOR;
startSector = startAddress / DEV_BYTES_PER_SECTOR;
if (startSector > lastSector) {
/*
* The offset is past the end of the partition.
*/
*numSectorsPtr = 0;
printf("Warning: ATCDiskIO: Past end of partition %d\n",
part);
return;
} else if ((startSector + totalSectors - 1) > lastSector) {
/*
* The transfer is at the end of the partition. Reduce the
* sector count so there is no overrun.
*/
totalSectors = lastSector - startSector + 1;
printf("Warning: ATCDiskIO: Overrun partition %d\n",
part);
}
(*diskAddrPtr) = startSector;
(*diskAddrPtr) += diskPtr->map[part].firstCylinder * cylinderSize;
*numSectorsPtr = totalSectors;
return;
}
/*
*----------------------------------------------------------------------
*
* SetupIOPB --
*
* What to do about the bp structure, and all the info passed to/from it?
*
* Setup a IOPB for a command. The IOPB can then
* be passed to SendCommand. It specifies everything the
* controller needs to know to do a transfer, and it is updated
* with status information upon completion.
*
* Results:
* None.
*
* Side effects:
* Set the various fields in the control block.
*
*----------------------------------------------------------------------
*/
static void
SetupIOPB(requestPtr, diskPtr, diskAddr, numSectors, address, IOPBPtr)
Request *requestPtr;
ATCDisk *diskPtr; /* Spefifies unit, drive type, etc */
register int diskAddr; /* Disk address of operation*/
int numSectors; /* Number of sectors to transfer */
register Address address; /* Address of the buffer */
struct iopbhdr *IOPBPtr; /* I/O Parameter Block */
{
ATCController *atcPtr = diskPtr->atcPtr;
int logicalBlock = diskAddr;
int byteCount = numSectors * DEV_BYTES_PER_SECTOR;
int index = IOPBPtr->index;
char cmd = requestPtr->command;
int bufSize = DEV_BYTES_PER_SECTOR * numSectors;
Address dmaAddress;
int amod;
if (atcDebug){
printf("Entered SetupIOPB.\n");
}
/*
* Determine DMA address and address modifier.
*/
if (VmMachIsXbusMem(address)) {
amod = A32BAMOD;
dmaAddress = address;
} else {
amod = A32WAMOD;
if (bufSize > 0) {
dmaAddress = (Address) VmMach_32BitDMAAlloc(bufSize, address);
} else {
dmaAddress = VMMACH_DMA_START_ADDR;
}
if ((unsigned) dmaAddress > (unsigned)VMMACH_DMA_START_ADDR) {
dmaAddress -= VMMACH_DMA_START_ADDR;
}
}
if (atcDebug){
printf("dmaBuffer size %d sectors mapped to dma address 0x%x\n",
numSectors, dmaAddress);
}
bzero((char *) &(IOPBPtr->iopb), sizeof(struct iopb));
IOPBPtr->bp = NULL; /* we are not using this */
IOPBPtr->iopb.command = requestPtr->command;
IOPBPtr->iopb.option = requestPtr->option;
IOPBPtr->iopb.reserved1 = 0x7f;
IOPBPtr->iopb.flags = requestPtr->flags;
IOPBPtr->iopb.log_array = 1; /* logical array number */
IOPBPtr->iopb.reserved2 = 0;
IOPBPtr->iopb.buffer = dmaAddress;
IOPBPtr->iopb.buf_addr_mod = amod;
IOPBPtr->iopb.intr_level = atcPtr->ilev;
IOPBPtr->iopb.intr_vector = atcPtr->ivec;
IOPBPtr->iopb.auxbuf_mod = 0;
IOPBPtr->iopb.sg_entries = 0; /* no scatter-gather */
IOPBPtr->iopb.auxbuf_size = 0;
IOPBPtr->iopb.aux_buffer = 0;
/*
* byte_count used to be byteCount
*/
switch (cmd) {
case CMD_READ:
IOPBPtr->iopb.byte_count = byteCount;
IOPBPtr->iopb.id = diskPtr->slaveID;
IOPBPtr->iopb.logical_block = logicalBlock;
break;
case CMD_WRITE:
IOPBPtr->iopb.byte_count = byteCount;
IOPBPtr->iopb.id = diskPtr->slaveID;
IOPBPtr->iopb.logical_block = logicalBlock;
break;
default:
printf("setup_iopb: invalid command %d\n", cmd);
free_iopb(atcPtr, IOPBPtr);
}
atcPtr->requestInfo[index].requestPtr = requestPtr;
atcPtr->requestInfo[index].dmaBuffer = dmaAddress;
atcPtr->requestInfo[index].dmaBufferSize = byteCount;
atcPtr->requestInfo[index].IOPBPtr = IOPBPtr;
}
/*
*----------------------------------------------------------------------
*
* reportError --
*
* Results:
*
* Side effects:
*
*----------------------------------------------------------------------
*/
static void
reportError(statusPtr)
struct status *statusPtr;
{
int etype = GET_ETYPE(statusPtr->status);
int estatus = GET_ESTATUS(statusPtr->status);
int ecmd = GET_ECMD(statusPtr->status);
int ecode = GET_ECODE(statusPtr->status);
if (atcDebug){
printf("Entered reportError.\n");
}
printf("ETYPE = %d, ESTATUS = %d, ECMD = %d, ECODE = %d\n",
etype, estatus, ecmd, ecode);
switch (etype){
case ET_CMD_SPEC:
printf("Error type ET_CMD_SPEC (command specific) \n");
break;
case ET_CMD_GEN:
printf("Error type ET_CMD_GEN (generic to all host commands)\n");
break;
case ET_ENVIRON:
printf("Error type ET_ENVIRON (environmental problems)\n");
break;
case ET_INFO:
printf("Error type ET_INFO (informational messages for host)\n");
break;
case ET_BKD_DIAG:
printf("Error type ET_BKD_DIAG (reported from bckgrnd diagnostics)\n");
break;
case ET_ABORT:
printf("Error type ET_ABORT (error contains abort code #)\n");
break;
case ET_INIT:
printf("Error type ET_INIT (for reporting initialization problems)\n");
break;
default:
printf("Problem!!! Unrecognized error type!\n");
}
switch (estatus) {
case ES_EMPTY:
printf("Error status ES_EMPTY (no status bits active)\n");
break;
case ES_SENSE_VALID:
printf("Error status ES_SENSE_VALID (sense data is valid)\n");
break;
case ES_NONFATAL:
printf("Error status ES_NONFATAL (host command completed successfully)\n");
break;
case ES_EXT_VALID:
printf("Error status ES_EXT_VALID (external error info is valid)\n");
break;
case ES_PASS_THRU:
printf("Error status ES_PASS_THRU (to log pass-thru ops to error log)\n");
break;
default:
printf("Problem!!! Unrecognized error status!\n");
}
switch (ecode) {
case EC_CMD:
printf("Error code EC_CMD -- invalid command in iopb\n");
break;
case EC_OPTION:
printf("Error code EC_OPTION -- invalid option in iopb\n");
break;
case EC_PRIORITY:
printf("Error code EC_PRIORITY -- invalid priority in iopb\n");
break;
case EC_LINK:
printf("Error code EC_LINK -- invalid linked_iopb in iopb\n");
break;
case EC_FLAGS:
printf("Error code EC_FLAGS -- invalid flags in iopb\n");
break;
case EC_ID:
printf("Error code EC_ID -- invalid id field in iopb\n");
break;
case EC_LOG_BLK:
printf("Error code EC_LOG_BLK -- invalid logical block in iopb\n");
break;
case EC_BYTE_CNT:
printf("Error code EC_BYTE_CNT -- invalid byte count in iopb\n");
break;
case EC_BUFFER:
printf("Error code EC_BUFFER -- invalid buffer address in iopb\n");
break;
case EC_BUFADDRMOD:
printf("Error code EC_BUFADDRMOD -- invalid buf address mod in iopb\n");
break;
case EC_INT_LEVEL:
printf("Error code EC_INT_LEVEL -- invalid interrupt level in iopb\n");
break;
case EC_AUXBUFMOD:
printf("Error code EC_AUXBUFMOD -- invalid aux buf mod in iopb\n");
break;
case EC_SG_ENTRIES:
printf("Error code EC_SG_ENTRIES -- invalid # s/g entries in iopb\n");
break;
case EC_AUXBUFSIZE:
printf("Error code EC_AUXBUFSIZE -- invalid aux buffer size in iopb\n");
break;
case EC_AUXBUFFER:
printf("Error code EC_AUXBUFFER -- invalid aux buff address in iopb\n");
break;
case EC_SG_COUNT:
printf("Error code EC_SG_COUNT -- invalid s/g count in iopb\n");
break;
case EC_SG_BUFFER:
printf("Error code EC_SG_BUFFER -- invalid s/g buffer in iopb\n");
break;
case EC_SG_AMOD:
printf("Error code EC_SG_AMOD -- invalid s/g buffer amod in iopb\n");
break;
default:
printf("Problem!!! Unrecognized error code!\n");
}
}
/*
*----------------------------------------------------------------------
*
* DevATCIntr --
*
* Handle interrupts from the ATC controller. This routine
* may start any queued requests.
*
* Results:
* TRUE if an ATC controller was responsible for the interrupt
* and this routine handled it.
*
* Side effects:
* Usually a process is notified that an I/O has completed.
*
*----------------------------------------------------------------------
*/
Boolean
DevATCIntr(clientData)
ClientData clientData;
{
ATCController *atcPtr = (ATCController *) clientData;
Request *requestPtr;
struct iopbhdr *iopbPtr;
struct status *statusPtr;
int index, returnVal;
ReturnStatus status;
int error;
if (atcDebug){
printf("Entered DevATCIntr.\n");
}
/* read fifo to get iopb index */
returnVal = get_fifo(atcPtr);
index = (returnVal & 0x7f);
error = (returnVal & 0x100);
if (atcDebug){
printf("Value from get_fifo is 0x%x; index after interrupt is 0x%x\n",
returnVal, index);
}
if (error == 0){
if (atcDebug){
printf("No error occurred on iopb\n");
}
} else {
printf("Error in iopb!!\n");
}
iopbPtr = &atcPtr->iopblist[index];
statusPtr = &atcPtr->statuslist[index];
requestPtr = atcPtr->requestInfo[index].requestPtr;
/*
* Release the DMA buffer if command mapped one.
*/
if (!VmMachIsXbusMem(atcPtr->requestInfo[index].dmaBuffer) &&
atcPtr->requestInfo[index].dmaBufferSize > 0) {
if (((unsigned)atcPtr->requestInfo[index].dmaBuffer) & 0x80000000) {
VmMach_32BitDMAFree(atcPtr->requestInfo[index].dmaBufferSize,
atcPtr->requestInfo[index].dmaBuffer);
} else {
VmMach_DMAFree(atcPtr->requestInfo[index].dmaBufferSize,
atcPtr->requestInfo[index].dmaBuffer);
}
atcPtr->requestInfo[index].dmaBufferSize = 0;
}
bzero((char *) &(atcPtr->requestInfo[index]), sizeof(perRequestInfo));
/*
* Need to signal error if detected
*/
{
int etype = GET_ETYPE(statusPtr->status);
int estatus = GET_ESTATUS(statusPtr->status);
/*
int ecmd = GET_ECMD(statusPtr->status);
int ecode = GET_ECODE(statusPtr->status);
*/
if (error == 0){
status = SUCCESS;
} else{
switch (etype) {
case ET_CMD_GEN:
case ET_CMD_SPEC:
reportError(statusPtr);
if (estatus & ES_NONFATAL) {
status = SUCCESS;
} else {
status = FAILURE;
}
break;
default:
reportError(statusPtr);
status = FAILURE;
break;
}
}
}
MASTER_LOCK(&(atcPtr->mutex));
free_iopb(atcPtr, iopbPtr);
MASTER_UNLOCK(&(atcPtr->mutex));
RequestDone(requestPtr->diskPtr,requestPtr,status,requestPtr->numSectors);
StartNextRequest(atcPtr);
return(TRUE);
}
/*
*----------------------------------------------------------------------
*
* RequestDone --
*
* Mark a request as done by calling the request's doneProc. DMA memory
* is released.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
RequestDone(diskPtr, requestPtr, status, numSectors)
ATCDisk *diskPtr;
Request *requestPtr;
ReturnStatus status;
int numSectors;
{
if (atcDebug){
printf("Entered RequestDone.\n");
}
if (numSectors > 0) {
if (requestPtr->requestPtr->operation == FS_READ) {
diskPtr->diskStatsPtr->diskStats.diskReads++;
} else {
diskPtr->diskStatsPtr->diskStats.diskWrites++;
}
}
(requestPtr->requestPtr->doneProc)(requestPtr->requestPtr, status,
numSectors*DEV_BYTES_PER_SECTOR);
}
/*
*----------------------------------------------------------------------
*
* StartNextRequest --
*
* Start the next request of an ATC controller.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
StartNextRequest(atcPtr)
ATCController *atcPtr;
{
ATCDisk *diskPtr;
Request *requestPtr;
int index;
if (atcDebug){
printf("Entered StartNextRequest.\n");
}
/*
* If the controller is busy, just return.
*/
MASTER_LOCK(&atcPtr->mutex);
while (atcPtr->free_iopbs != NULL) {
requestPtr = (Request *) Dev_QueueGetNextFromSet(atcPtr->ctrlQueues,
DEV_QUEUE_ANY_QUEUE_MASK, (ClientData *) &diskPtr);
if (requestPtr == (Request *) NIL) {
break;
}
index = alloc_iopb(atcPtr)->index;
MASTER_UNLOCK(&atcPtr->mutex);
SendCommand(diskPtr, requestPtr, FALSE, index);
MASTER_LOCK(&atcPtr->mutex);
}
MASTER_UNLOCK(&atcPtr->mutex);
}